package com.triplelink.dao.impl.openrdf;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.openrdf.model.Literal;
import org.openrdf.model.Value;
import org.openrdf.query.BindingSet;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.Update;
import org.openrdf.query.UpdateExecutionException;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;

import com.triplelink.builder.query.QueryTL;
import com.triplelink.context.Connector;
import com.triplelink.context.UserConnector;
import com.triplelink.exception.TripleLinkException;
import com.triplelink.util.ListUtil;

public class BaseDAOOpenrdf extends UserConnector {
	
	public BaseDAOOpenrdf(Connector connector)
	{
		super(connector);
	}
	
	protected Update prepareUpdate(RepositoryConnection conn, String queryString) {
		
		try
		{
			return conn.prepareUpdate(QueryLanguage.SPARQL, getPrefixs() + queryString);
		}
		catch (RepositoryException e)
		{
			throw new TripleLinkException(e);
		}
		catch (MalformedQueryException e)
		{
			throw new TripleLinkException(e);
		}
	}
	
	protected TupleQuery prepareTupleQuery(RepositoryConnection conn, QueryLanguage queryLanguage, String queryString) {
		
		try
		{
			return conn.prepareTupleQuery(queryLanguage, getPrefixs() + queryString);
		}
		catch (RepositoryException e)
		{
			throw new TripleLinkException(e);
			
		}
		catch (MalformedQueryException e)
		{
			throw new TripleLinkException(e);
		}
	}
	
	protected TupleQuery prepareTupleQuery(RepositoryConnection conn, String queryString) {
		
		return prepareTupleQuery(
				conn,
				QueryLanguage.SPARQL,
				queryString
		);
	}
	
	protected String getPrefixs ()
	{
		
		return "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n" +
			   "PREFIX owl: <http://www.w3.org/2002/07/owl#> \n" +
			   "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" +
			   "PREFIX tipos: <http://semantica.infoglobo.com.br/tipos/> \n" +
			   "PREFIX telas: <http://semantica.infoglobo.com.br/telas/> \n" ;
	}
	
	protected Literal createLiteral (String value)
	{
		return getValueFactory().createLiteral(value);
	}
	
	protected Literal createInteger(int value)
	{
		return createInteger(String.valueOf(value));
	}
	
	protected Literal createInteger(String value)
	{
		return getValueFactory().createLiteral(value, createURI("http://www.w3.org/2001/XMLSchema#integer"));
	}
	
	protected String getString(String varName, BindingSet result)
	{
		Value value = result.getValue(varName);
		
		if (value == null) {
			
			return null;
		}
		
		return value.stringValue();
	}
	
	protected String getNumeric(String varName, BindingSet result)
	{
		Value value = result.getValue(varName);
		
		if (value == null) {
			
			return null;
		}
		
		String valueStr = value.stringValue();
		
		int eIndex = valueStr.indexOf('E');
				
		if (eIndex != -1) {
			
			int dotIndex = valueStr.indexOf('.');
			
			String left = valueStr.substring(0, eIndex);
			String right = valueStr.substring(eIndex + 1);
			
			if (dotIndex == -1) {
				
				return String.valueOf(Long.parseLong(left) * (Math.pow(10,Long.parseLong(right))));
			}
			
			return String.valueOf(Double.parseDouble(left) * (Math.pow(10, Long.parseLong(right))));
		}
				
		return valueStr;
	}
	
	protected List<String> getListString(String varName, BindingSet result)
	{
		String valoresConcatenados = getString(varName, result);
		
		if (valoresConcatenados == null) {
			
			return new ArrayList<String>();
		}
		
		return ListUtil.montarList(valoresConcatenados.split(",\\s*"));
	}
	
	protected boolean getBoolean(String varName, BindingSet result)
	{
		Value value = result.getValue(varName);
		
		if (value == null) {
			
			return false;
		}
		
		String valueStr = value.stringValue();
		
		return "true".equals(valueStr) || "1".equals(valueStr);
	}
	
	public String makeCSVBindingLabel(String label, int size)
	{
		StringBuilder sb = new StringBuilder();
		
		for (int i = 0; i < size; i++) {
			
			sb.append(label);
			sb.append('_');
			sb.append(i);
			sb.append(',');
			sb.append(' ');
		}
		
		if (sb.length() > 2) {

			sb.replace(sb.length() - 2, sb.length(), "");
		}
		
		return sb.toString();
	}
	
	public void putCVSBindURIs(String label, List<String> values, TupleQuery tupleQuery)
	{
		for (int i = 0; i < values.size(); i++)
		{
			tupleQuery.setBinding(label + "_" + i, createURI(values.get(i)));
		}
	}
	
	protected Value createLiteral(String value, String onDataRange)
	{
		return getValueFactory().createLiteral(value, createURI(onDataRange));
	}
	
	protected String makeUrisLabels(String variable, List<String> uris)
	{
		if (uris == null)
			return "";
		
		StringBuilder sb = new StringBuilder();
		
		for (int i = 0; i < uris.size(); i++)
		{
			sb.append("?" + variable + "_" + i + ", \n");
		}
		
		if (sb.length() == 0)
			return "";
		
		return sb.substring(0, sb.length() - 3) + " \n";
	}
	
	protected String makeUrisLabels(String prefix, String variable, String sufix, List<String> uris)
	{
		if (uris == null)
			return "";
		
		StringBuilder sb = new StringBuilder();
		
		for (int i = 0; i < uris.size(); i++)
		{
			sb.append(prefix + "?" + variable + "_" + i + sufix + ", \n");
		}
		
		if (sb.length() == 0) {
			
			return "";
		}
		
		return sb.substring(0, sb.length() - 3) + " \n";
	}
	
	protected void putUrisBinds(String variable, List<String> uris, TupleQuery tupleQuery)
	{
		if (uris == null)
			return;
		
		for (int i = 0; i < uris.size(); i++)
		{
			tupleQuery.setBinding(variable + "_" + i, createURI(uris.get(i)));
		}
	}
	
	protected void executeUpDate(QueryTL queryTL)
	{
		
		Update tupleQuery = prepareUpdate(getConnection(), queryTL.getSb().toString());
		
		putBinds(queryTL.getBindings(), tupleQuery);
		
		try
		{
			
	         tupleQuery.execute();
	        
		} catch (UpdateExecutionException e) {
			 
			throw new TripleLinkException(e);
			
		} finally {
			
			closeConnection();
		}
	}
	
	protected void putBinds(Map<String, Value> binds, Update tupleQuery)
	{
		for (String label : binds.keySet())
		{
			tupleQuery.setBinding(label, binds.get(label));
		}
	}
}